﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ClusHal
{
    class Action
    {
        public static char[] preferences = null;

        private List<double> values;
        private string label;
        private Cluster cluster = null;

        /// <summary>
        /// Lista wariantów dominowanych przez ten wariant
        /// </summary>
        private List<Action> dominates;

        /// <summary>
        /// Lista wariantów dominowanych przez ten wariant
        /// </summary>
        internal List<Action> Dominates
        {
            get { return dominates; }
        }

        /// <summary>
        /// Lista wariantów dominujących ten wariant
        /// </summary>
        private List<Action> dominated;

        /// <summary>
        /// Lista wariantów dominujących ten wariant
        /// </summary>
        internal List<Action> Dominated
        {
            get { return dominated; }
        }

        internal Cluster Cluster
        {
            get { return cluster; }
            set { cluster = value; }
        }

        public string Label
        {
            get { return label; }
            set { label = value; }
        }

        public Action(int size)
        {
            dominated = new List<Action>();
            dominates = new List<Action>();
            values = new List<double>();
            for (int i = 0; i < size; i++)
            {
                values.Add(0);
            }
        }

        public Action(double[] vals)
        {
            dominated = new List<Action>();
            dominates = new List<Action>();
            values = new List<double>();
            for (int i = 0; i < vals.Length; i++)
                values.Add(vals[i]);
        }

        public Action(string s,bool n)
        {
            dominated = new List<Action>();
            dominates = new List<Action>();
            values = new List<double>();
            char[] sep = { '\t' };
            string[] items = s.Split(sep);
            if (n)
            {
                foreach (string i in items)
                {
                    if (i != "")
                        values.Add(double.Parse(i));
                    else
                        values.Add(0);
                }
            }
            else
            {
                label = items[0];
                for (int i = 1; i < items.Length - 1; i++)
                {
                    if (items[i] != "")
                        values.Add(double.Parse(items[i]));
                    else
                        values.Add(0);
                }
            }
        }


        /// <summary>
        /// Konstruktor kopiujący
        /// </summary>
        /// <param name="a"></param>
        public Action(Action a)
        {
            dominated = new List<Action>();
            dominates = new List<Action>();
            values = new List<double>();
            foreach (double v in a.values)
            {
                values.Add(v);
            }
        }

        /// <summary>
        /// Wczytuje informacje dotyczące preferencji
        /// + - kryterium zysku
        /// - - kryterium kosztu
        /// # - pomiń to kryterium
        /// @ - decyzja
        /// </summary>
        /// <param name="line"></param>
        public static void LoadPreferences(string line)
        {
            char[] sep = { '\t' };
            string[] items = line.Split(sep);
            preferences = new char[items.Length];
            for (int i = 0; i < items.Length; i++)
            {
                preferences[i] = char.Parse(items[i]);
            }
        }

        /// <summary>
        /// Czy kryterium brać pod uwagę przy obliczaniu odległości
        /// </summary>
        /// <param name="i">Indeks kryterium</param>
        /// <returns>true jeżeli ma być wykorzystywane</returns>
        public static bool ValidCriterion(int i)
        {
            char c = preferences[i];
            if (c == '+' || c == '-')
                return true;
            return false;
        }

        public static void PrintPreferences()
        {
            Console.WriteLine("Preferences");
            foreach (char v in preferences)
            {
                Console.WriteLine(v.ToString());
            }
        }

        public int Size
        {
            get
            {
                return values.Count;
            }
        }

        public double this[int index]
        {
            get
            {
                return values[index];
            }
            set
            {
                values[index] = value;
            }
        }

        public override string ToString()
        {
            return Label;
        }

        public bool isDominating(Action b)
        {
            for (int i = 0; i < values.Count; i++)
            {
                if ((values[i] < b[i])&&preferences[i]=='+')
                {
                    return false;
                }
                if ((values[i] > b[i]) && preferences[i]=='-')
                {
                    return false;
                }

            }
            return true;

            //bool result = false;
            //for (int i = 0; i < values.Count; i++)
            //{
            //    if (values[i] < b[i])
            //    {
            //        return false;
            //    }
            //    if (values[i] > b[i])
            //        result = true;
            //}
            //return result;
        }

        public void CalculateSets(List<Action> data)
        {
            dominates = new List<Action>();
            dominated = new List<Action>();
            foreach (Action a in data)
            {
                //if (a != this)
                {
                    if (isDominating(a))
                        dominates.Add(a);
                    if (a.isDominating(this))
                        dominated.Add(a);
                }
            }
        }

        /// <summary>
        /// Zlicza warianty dominujące ten wariant z klasy nie lepszej niż parametr
        /// </summary>
        /// <param name="cl">Klasa decyzyjna</param>
        /// <returns>Liczba wariantów dominujących</returns>
        public int CountDominatedByClassAM(int cl)
        {
            if (dominated.Count > 0)
            {
                int c = 0;
                foreach (Action a in dominated)
                {
                    if (a.Cluster.DecisionClass < cl)
                        c++;
                }
                return c;
            }
            return -1;
        }

        public int CountDominatedByClassAL(int cl)
        {
            if (dominated.Count > 0)
            {
                int c = 0;
                foreach (Action a in dominated)
                {
                    if (a.Cluster.DecisionClass <= cl)
                        c++;
                }
                return c;
            }
            return -1;
        }

        /// <summary>
        /// Zlicza warianty dominowane przez ten wariant należące do klasy nie gorszej niż parametr
        /// </summary>
        /// <param name="cl">Klasa decyzyjna</param>
        /// <returns>Liczba wariantów zdominowanych</returns>
        public int CountDominatesByClassAL(int cl)
        {
            if (dominates.Count > 0)
            {
                int c = 0;
                foreach (Action a in dominates)
                {
                    if (a.Cluster.DecisionClass >= cl)
                        c++;
                }
                return c;
            }
            return -1;
        }

        public int CountDominatesByClassAM(int cl)
        {
            if (dominates.Count > 0)
            {
                int c = 0;
                foreach (Action a in dominates)
                {
                    if (a.Cluster.DecisionClass > cl)
                        c++;
                }
                return c;
            }
            return -1;
        }

        public void SaveToFile(StreamWriter sw)
        {
            StringBuilder sb = new StringBuilder(label);
            sb.Append("\t");
            foreach (double v in values)
            {
                sb.Append(v.ToString());
                sb.Append("\t");
            }
            sb.Append(cluster.DecisionClass.ToString());
            sw.WriteLine(sb.ToString());
        }
    }
}
